import { think } from 'thinkjs';

// import RestModelClass, { RestOption } from "src/types/utils/rest";
import Base, { ServiceOption } from '../../../../../service/base';
import { IUser, IImConnectData, ILoginPort, IDeviceType, ILoginPortOs, IImDeviceEvent } from '../../types';
import { IServiceCloudImUserCreateParams, IServiceCloudImUserCreateResult } from '../../types/service/User';
import mongo from '../../../../../utils/mongo';
import { SchemaUser } from '../../types/model/User';
import { syncValidate } from '../../../../utils/validate';

import { $redis } from '../utils/redis';
import SessionServiceClass from './session';
import MessageServiceClass from './msg';

export class ImConnectServiceClass extends Base<IUser> {
  constructor(option: ServiceOption) {
    super(option);
  }

  /**
   * 创建云通信ID
   */
  async connectIn(params: {
    client: string;
    account: string;
    token: string;
    deviceId: string;
    type: IDeviceType;
    os: ILoginPortOs;
    socketId: string;
    ip: string;
  }): Promise<void> {
    console.log('[connectIn] ', params);
    const { type, os, deviceId, account, token, client, socketId, ip } = params;
    // 鉴权开始

    // 鉴权通过
    let loginPort: ILoginPort = {
      type,
      os,
      deviceId,
      account,
      connectionId: socketId,
      ip,
      time: Date.now(),
      online: true,
    };
    let imLoginData: IImConnectData = {
      online: true,
      loginports: [],
    };
    // 查询缓存中的用户连接信息
    const key = `mim_lg_${account}`;
    // 加锁
    await $redis.set(key + '_lc', 'lock', 'EX', 1, 'NX');
    const imLoginDataCache: string | null = await $redis.get(key);
    // console.log('[imLoginDataCache] ', imLoginDataCache);
    if (imLoginDataCache) {
      try {
        let _imLoginData = JSON.parse(imLoginDataCache);
        // 校验数据
        if (typeof _imLoginData === 'object' && _imLoginData.loginports) {
          imLoginData = _imLoginData;
        }
      } catch (e) {}
    }
    // 查找是否已经连接
    let i = imLoginData.loginports.findIndex((item) => item.deviceId === deviceId);
    if (i > -1) {
      imLoginData.loginports[i] = {
        ...loginPort,
      };
    } else {
      imLoginData.loginports.push(loginPort);
    }
    // 更新在线
    imLoginData.online = true;
    // 写入缓存
    const writeRedisRes = await $redis.set(key, JSON.stringify(imLoginData), 'EX', 86400);
    console.log('[writeRedisRes] ', writeRedisRes);
    // socketId关联存储到account
    const writeAccountSocketRes = await $redis.set('mim_sck_' + socketId, account, 'EX', 86400);
    console.log('[writeAccountSocketRes] ', writeAccountSocketRes);
    // 释放锁
    await $redis.del(key + '_lc');
    // 发送给客户端提示登录成功
    (think.app as any).websocket.io.to(loginPort.connectionId).emit('imevent', {
      type: 'login',
    });
  }

  async connectOut(socketId: string) {
    console.log('[connectOut] ', socketId);
    const socketIdKey = 'mim_sck_' + socketId;
    const account = await $redis.get(socketIdKey);
    console.log('[account] ', account);
    if (account) {
      const key = `mim_lg_${account}`;
      // 加锁
      await $redis.set(key + '_lc', 'lock', 'EX', 1, 'NX');
      const imLoginDataCache: string | null = await $redis.get(key);
      // console.log('[imLoginDataCache] ', imLoginDataCache);
      if (imLoginDataCache) {
        try {
          let imLoginData: IImConnectData = JSON.parse(imLoginDataCache);
          if (typeof imLoginData === 'object' && imLoginData.loginports) {
            const { loginports } = imLoginData;
            const i = loginports.findIndex((item) => item.connectionId === socketId);
            if (i > -1) {
              imLoginData.loginports.splice(i, 1);
            }
          }
          if (imLoginData.loginports.length > 0) {
            // 更新
            const writeRedisRes = await $redis.set(key, JSON.stringify(imLoginData), 'EX', 86400);
            console.log('[writeRedisRes] ', writeRedisRes);
          } else {
            // 删除
            await $redis.del(key);
          }
        } catch (e) {}
      }
      // 删除socketId关联
      await $redis.del(socketIdKey);
      // 释放锁
      await $redis.del(key + '_lc');
    }
  }

  /**
   * 获取用户连接信息
   */
  async getClientLogport({
    account,
  }: {
    account: string;
  }): Promise<{
    imLoginData?: IImConnectData;
  }> {
    // 查询缓存中的用户连接信息
    const key = `mim_lg_${account}`;
    const imLoginDataCache: string | null = await $redis.get(key);
    if (imLoginDataCache) {
      try {
        let imLoginData: IImConnectData = JSON.parse(imLoginDataCache);
        return {
          imLoginData,
        };
      } catch (e) {
        return {};
      }
    }
    return {};
  }

  /**
   * 向客户端发送事件消息
   */
  async sendMessageToClient({
    account,
    clients,
    message,
  }: {
    account: string;
    clients?: string[];
    message: IImDeviceEvent;
  }): Promise<{
    online?: boolean;
  }> {
    let { imLoginData } = await this.getClientLogport({ account });
    if (imLoginData && imLoginData.loginports) {
      // 在线
      imLoginData.loginports.forEach((loginPort) => {
        try {
          (think.app as any).websocket.io.to(loginPort.connectionId).emit('imevent', message);
          // console.log('[发送成功] ', loginPort.connectionId);
        } catch (e) {
          console.log('[发送失败] ', loginPort.connectionId);
        }
      });
      // 返回结果
      return {
        online: true,
      };
    } else {
      // 不在线
      return {
        online: false,
      };
    }
  }

  /**
   * 接收来自客户端的消息
   */
  async onClientEvent(eventMsg: IImDeviceEvent) {
    if (eventMsg.type === 'setCurrSession') {
      const sessionService = think.service('cloudim_session') as SessionServiceClass;
      sessionService.setCurrSession(eventMsg);
    }
    if (eventMsg.type === 'updateSession') {
      const sessionService = think.service('cloudim_session') as SessionServiceClass;
      sessionService.updateSession(eventMsg);
    }
    if (eventMsg.type === 'invokeDeleteSession') {
      const sessionService = think.service('cloudim_session') as SessionServiceClass;
      sessionService.deleteSession(eventMsg);
    }
    if (eventMsg.type === 'msgRcvAck') {
      const messageService = think.service('cloudim_msg') as MessageServiceClass;
      messageService.onRsgRcvAck(eventMsg);
    }
  }
}

export default ImConnectServiceClass;
